package isssr.entity.src;

import isssr.entity.exception.IllegalOrganizationalGoalCreationException;
import isssr.entity.exception.IllegalOrganizationalGoalCreationExceptionCode;
import isssr.entity.exception.IllegalOrganizationalGoalUpdateException;
import isssr.entity.exception.IllegalOrganizationalGoalUpdateExceptionCode;
import isssr.entity.src.GoalStatus;
import isssr.entity.src.User;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class OrganizationalGoal implements Serializable{

	private Integer 	gid;
	private String 		title;
	private String 		description;
	private Integer 	priority;
	private Integer 	status;
	private User 		goalOwner;
	private User 		goalEnactor;
	private Set<User> 	superSet;
	private String 		focus;
	private String 		object;
	private String 		magnitude;
	private String 		timeframe;
	private String 		organizationalScope;
	private String 		constraints;
	private String 		relations;

	// this constructor is for Hibernate
	private OrganizationalGoal() {}
	
	public OrganizationalGoal(String title, User owner) throws IllegalOrganizationalGoalCreationException 
	{	
		if(owner == null)
			throw new IllegalOrganizationalGoalCreationException(IllegalOrganizationalGoalCreationExceptionCode.ILLEGAL_GOAL_OWNER);
		
		if(title == null || title.length() == 0)
			throw new IllegalOrganizationalGoalCreationException(IllegalOrganizationalGoalCreationExceptionCode.ILLEGAL_TITLE);

		this.goalOwner 	= owner;
		this.title 		= title;
		this.status  	= 0;
		this.superSet 	= new HashSet<User>();
	}

	
	public OrganizationalGoalDTO getDTO()
	{
		OrganizationalGoalDTO data = new OrganizationalGoalDTO(title, description, priority, this.getGoalStatus(), goalOwner, goalEnactor, superSet, focus, object, magnitude, timeframe, organizationalScope, constraints, relations);	
		return data;
	}
	
	
	public void updateOrganizationalGoal(OrganizationalGoalDTO data) throws IllegalOrganizationalGoalUpdateException
	{
		if(!this.getGoalStatus().equals(GoalStatus.DEFINITION))
			throw new IllegalOrganizationalGoalUpdateException(IllegalOrganizationalGoalUpdateExceptionCode.ILLEGAL_STATUS);
		
		if(!this.verifyTitle(data.getTitle()))
			throw new IllegalOrganizationalGoalUpdateException(IllegalOrganizationalGoalUpdateExceptionCode.ILLEGAL_TITLE);
		
		if(!this.verifyEqualGoalOwner(data.getGoalOwner()))
			throw new IllegalOrganizationalGoalUpdateException(IllegalOrganizationalGoalUpdateExceptionCode.ILLEGAL_GOAL_OWNER);
		
		if(!this.verifyGoalEnactor(data.getGoalEnactor(), data.getGoalOwner()))
			throw new IllegalOrganizationalGoalUpdateException(IllegalOrganizationalGoalUpdateExceptionCode.ILLEGAL_GOAL_ENACTOR);
		
		if(!this.verifySuperOwnerList(data.getSuperList(), data.getGoalOwner()))
			throw new IllegalOrganizationalGoalUpdateException(IllegalOrganizationalGoalUpdateExceptionCode.ILLEGAL_SUPER_OWNER);
 
		this.performUpdateOrganizationalGoal(data);
	}

	
	private boolean verifyTitle(String title) {
		if(title == null || title.length() == 0)
			return false;
		else
			return true;
	}
	

	private boolean verifyEqualGoalOwner(User goalOwner) {
		if(this.goalOwner.equals(goalOwner))
			return true;
		else
			return false;
	}
	
	
	private boolean verifyGoalEnactor(User goalEnactor, User goalOwner) {
		if(goalEnactor != null && goalEnactor.compareLevel(goalOwner) > 0)
			return false;
		else 
			return true;
	}
	
	
	private boolean verifySuperOwnerList(List<User> superOwnerList, User goalOwner) {
		for(User superOwner : superOwnerList)
		{
			if( (superOwner.compareLevel(goalOwner) < 0) || superOwner.equals(goalOwner) )
				return false;
		}
		
		return true;
	}
	
	
	private void performUpdateOrganizationalGoal(OrganizationalGoalDTO goalData) {
		this.title 					= goalData.getTitle();
		this.description 			= goalData.getDescription();
		this.priority 				= goalData.getPriority();
		this.goalOwner 				= goalData.getGoalOwner();
		this.goalEnactor 			= goalData.getGoalEnactor();
		this.superSet 				= new HashSet<User>(goalData.getSuperList());
		this.focus 					= goalData.getFocus();
		this.object					= goalData.getObject();
		this.magnitude				= goalData.getMagnitude();
		this.timeframe				= goalData.getTimeframe();
		this.organizationalScope 	= goalData.getOrganizationalScope();
		this.constraints			= goalData.getConstraints();
		this.relations 				= goalData.getRelations();
	}
	
	
	public GoalStatus getGoalStatus() {
		
		switch(this.status.intValue())
		{
			case 0 : return GoalStatus.DEFINITION;
			case 1 : return GoalStatus.ELICITATION_VOTE;
			case 2 : return GoalStatus.FEASIBILITY_ANALYSIS;
			case 3 : return GoalStatus.DEVELOPEMENT;
			case 4 : return GoalStatus.COMPLETED;
			default: return null;
		}
	}
	
	
	@Override
	public boolean equals(Object o)
	{
		if(o==null)
			return false;
		if(! (o instanceof OrganizationalGoal))
			return false;
		
		OrganizationalGoal otherGoal = (OrganizationalGoal) o;
		
		Field[] userFields = this.getClass().getDeclaredFields();
		
		Object value1;
		Object value2;
		
		for(Field field : userFields)
		{
			try
			{
				value1 = field.get(this);
				value2 = field.get(otherGoal);
				
				if((value1 == null && value2 != null)
						|| ( value1 != null && !value1.equals(value2) ))
					return false;
			}
			catch(ReflectiveOperationException ex)
			{
				ex.printStackTrace();
			}
		}
		
		return true;
	}
	
	
	@Override
	public String toString()
	{
		String output = "OrganizationalGoal[";
		
		Field[] userFields = this.getClass().getDeclaredFields();
		
		Object value1;
		Boolean firstParam = Boolean.TRUE;
		
		for(Field field : userFields)
		{
			try
			{
				if(firstParam == Boolean.TRUE)
					firstParam = Boolean.FALSE;
				else
					output += ", ";
				
				value1 = field.get(this);
				
				if(value1 != null)
				{	
					output +=  value1.toString();
				}
				else
				{
					output += "null";
				}
			}
			catch(ReflectiveOperationException ex)
			{
				ex.printStackTrace();
			}
		}
		output += "]";
		
		return output;
	}

	
	private Integer getGid() {
		return gid;
	}

	private String getTitle() {
		return title;
	}

	private String getDescription() {
		return description;
	}

	private Integer getPriority() {
		return priority;
	}

	private Integer getStatus() {
		return status;
	}

	private User getGoalOwner() {
		return goalOwner;
	}

	private User getGoalEnactor() {
		return goalEnactor;
	}

	private Set<User> getSuperSet() {
		return superSet;
	}

	private String getFocus() {
		return focus;
	}

	private String getObject() {
		return object;
	}

	private String getMagnitude() {
		return magnitude;
	}

	private String getTimeframe() {
		return timeframe;
	}

	private String getOrganizationalScope() {
		return organizationalScope;
	}

	private String getConstraints() {
		return constraints;
	}

	private String getRelations() {
		return relations;
	}

	private void setGid(Integer id) {
		this.gid = id;
	}

	private void setTitle(String title) {
		this.title = title;
	}

	private void setDescription(String description) {
		this.description = description;
	}

	private void setPriority(Integer priority) {
		this.priority = priority;
	}

	private void setStatus(Integer status) {
		this.status = status;
	}

	private void setGoalOwner(User goalOwner) {
		this.goalOwner = goalOwner;
	}

	private void setGoalEnactor(User goalEnactor) {
		this.goalEnactor = goalEnactor;
	}

	private void setSuperSet(Set<User> superSet) {
		this.superSet = superSet;
	}

	private void setFocus(String focus) {
		this.focus = focus;
	}

	private void setObject(String object) {
		this.object = object;
	}

	private void setMagnitude(String magnitude) {
		this.magnitude = magnitude;
	}

	private void setTimeframe(String timeframe) {
		this.timeframe = timeframe;
	}

	private void setOrganizationalScope(String organizationalScope) {
		this.organizationalScope = organizationalScope;
	}

	private void setConstraints(String constraints) {
		this.constraints = constraints;
	}

	private void setRelations(String relations) {
		this.relations = relations;
	}
	
	
}
